home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
languags
/
a68k242.4
< prev
next >
Wrap
Text File
|
1989-03-08
|
56KB
|
1,852 lines
Path: xanth!ukma!tut.cis.ohio-state.edu!mailrus!bbn!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i026: a68k - 68000 assembler v2.42, Part04/04
Message-ID: <12037@swan.ulowell.edu>
Date: 8 Mar 89 01:50:35 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 1841
Approved: page@swan.ulowell.edu
Submitted-by: jlydiatt@jlami.wimsey.bc.ca (Jeff Lydiatt)
Posting-number: Volume 89, Issue 26
Archive-name: languages/a68k242.4
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# Symtab.c
# Operands.c
# This archive created: Tue Mar 7 20:42:31 1989
cat << \SHAR_EOF > Symtab.c
/*------------------------------------------------------------------*/
/* */
/* MC68000 Cross Assembler */
/* */
/* Copyright (c) 1985 by Brian R. Anderson */
/* */
/* Symbol table manipulation - January 6, 1989 */
/* */
/* This program may be copied for personal, non-commercial use */
/* only, provided that the above copyright notice is included */
/* on all copies of the source code. Copying for any other use */
/* without the consent of the author is prohibited. */
/* */
/*------------------------------------------------------------------*/
/* */
/* Originally published (in Modula-2) in */
/* Dr. Dobb's Journal, April, May, and June 1986. */
/* */
/* AmigaDOS conversion copyright 1989 by Charlie Gibbs. */
/* */
/*------------------------------------------------------------------*/
#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"
long Value; /* Passed from ReadSymTab to CalcValue */
/* Functions */
extern int Instructions(), ObjDir();
extern int GetInstModeSize(), GetMultReg();
extern int GetArgs(), GetAReg();
extern long AddrBndW(), AddrBndL();
char *AddName();
struct SymTab *NextSym();
struct SymTab **HashIt();
int LineParts(), ReadSymTab(), OpenIncl(), CountNest();
long GetValue(), CalcValue();
char *GetField();
int OpenIncl (name, dirlist) char *name, *dirlist;
/* Opens the file whose name is in "name". The current
directory is tried first. If that fails, the directory
names in "dirlist" (separated by commas) are then tried
until either a file is found or the list is exhausted.
If the file is found in a subdirectory, "name" is
modified to include the entire path specification.
If another input file is open when this routine is called,
it is closed first. Returns TRUE if successful, FALSE if not. */
{
register char *s, *t;
char dirname[MAXLINE];
if (In.fd != NULL)
close (In.fd); /* Close the inner file */
if ((In.fd = open (name, 0)) != -1) {
In.Ptr = In.Lim = In.Buf;
if (Quiet < 0)
fprintf (stderr, "\n%s line ", name);
return (TRUE); /* Found it in current directory */
}
s = dirlist;
while (*s) {
s = GetField (s, dirname);
t = dirname + strlen (dirname) - 1;
if ((*t != '/') && (*t != ':'))
strcat (dirname, "/"); /* Slash after directory name */
strcat (dirname, name);
if ((In.fd = open (dirname, 0)) != -1) {
In.Ptr = In.Lim = In.Buf;
strcpy (name, dirname); /* Return entire path */
if (Quiet < 0)
fprintf (stderr, "\n%s line ", name);
return (TRUE); /* Found it in a subdirectory */
}
if (*s)
s++; /* Skip over separator and try again */
}
In.fd = NULL;
return (FALSE); /* Couldn't find it anywhere */
}
int LineParts (dummy) int dummy;
/* Gets the next statement and extracts its component parts.
If end of file is reached, and we're in a macro or include
file, the file is closed and the next outermost file is
continued. If we have reached the end of the source file, or
encounter an ENDM or MEXIT directive within a macro expansion,
the current input file is closed and TRUE is returned.
If we're in a user macro (indicated by UPtr being nonzero),
we'll get the next statement from the save area in memory instead.
Macro arguments, if any, are substituted.
LineCount is incremented if a statement was successfully read.
If this is the first call of this routine (i.e. LineCount is zero)
and HeaderFN is not a null string, we'll return an INCLUDE statement
requesting the specified header file, rather than reading the first
statement from the source file.
The following fields are set up:
Line - statement line image
Label - instruction label (without trailing colon)
OpCode - instruction mnemonic (converted to upper case)
SrcOp - first (source) operand
DestOp - second (destination) operand
Size - size from OpCode
LabLoc - displacement to start of instruction label
OpLoc - displacement to start of instruction mnemonic
SrcLoc - displacement to start of source operand
DestLoc - displacement to start of destination operand
InFNum - decremented if end of file is reached
InF - incremented if end of file is reached
LabLine - set to LineCount if this line is labeled
(unless it's a local label)
*/
{
register int i, c;
int eofflag;
char *x;
while (1) { /* Repeat until we get something (not end of INCLUDE) */
Line[0] = Label[0] = OpCode[0] = SrcOp[0] = DestOp[0] = '\0';
LabLoc = OpLoc = SrcLoc = DestLoc = 0;
Src.Mode = Dest.Mode = NULL;
FwdShort = FALSE;
if ((LineCount==0) && (HeaderFN[0])) { /* Header file */
strcpy (Line, " INCLUDE "); /* Make an INCLUDE stmt. */
strcat (Line, HeaderFN);
strcat (Line, " ;Generated for header file");
strcpy (OpCode, "INCLUDE"); /* Dummy op code */
OpLoc = 8;
strcpy (SrcOp, HeaderFN); /* Dummy source operand */
SrcLoc = 16;
LineCount++;
ErrLim = AddrAdv = InstSize = nO = nS = nD = nX = 0;
PrntAddr = FALSE;
return (FALSE);
}
if (InF->UPtr != 0) { /* User macro input */
GetMacLine (dummy);
eofflag = FALSE;
} else { /* Normal file input */
eofflag = GetLine (dummy);
}
if ((Line[0] != '\0') && (Line[0] != '*') && (Line[0] != ';')) {
SubArgs (dummy); /* Substitute macro arguments */
GetParts (dummy); /* Break Line into its component parts */
}
/* ------ If we have reached the end of a macro or ------ */
/* ------ include file, return to the calling file ------ */
i = eofflag; /* End of file */
if (i) {
if (SkipNest != 0) {
Error (OpLoc, NoENDC); /* ENDC is missing */
WriteListLine (&List); /* It's not normally listed */
SkipNest = 0;
}
} else if ((InF->NArg != -1)&&(Dir != Macro)) { /* Macro exits */
if (strcmp (OpCode, "ENDM") == 0) {
i = TRUE;
(InF->Line)++; /* Count ENDM directive */
if (SkipNest != 0) {
Error (OpLoc, NoENDC); /* ENDC is missing */
WriteListLine (&List); /* It's not normally listed */
SkipNest = 0;
}
} else if (SkipNest == 0) {
if (strcmp (OpCode, "MEXIT") == 0) {
i = TRUE;
(InF->Line)++; /* Count MEXIT directive */
}
}
}
if (!i) { /* Not end of file or macro */
if (PrevDir == MacCall) {
if (strcmp (OpCode, "MACRO") == 0) {
(InF->Line)++; /* Count macro header */
continue; /* and ignore it. */
}
}
if (SkipNest == 0) { /* If we're not skipping, */
break; /* we got something. */
} else {
(InF->Line)++; /* Count skipped lines */
SkipNest += CountNest (OpCode); /* Adjust SkipNest */
continue;
}
}
if (!Pass2 && (IncStart != 0) && (IncPtr == InF)) {
SkipLim->Start = IncStart; /* End of skippable INCLUDE */
SkipLim->Finish=LineCount; /* Save line numbers for pass 2 */
SkipLim->MCount = MacCount; /* Save macro counter too */
if (SkipLim->Set1 != NULL) {
SetFixLim--;
x = (char *) SkipLim + sizeof (struct SkipEnt);
if (x > (char *) SetFixLim) {
SetFixLim++; /* No room for final entry */
} else {
SetFixLim->Sym = NULL; /* Null entry */
SetFixLim->Val = 0; /* indicates end of */
SetFixLim->Hunk = 0; /* SET symbol list. */
}
}
SkipLim++;
IncStart = 0;
}
if (InFNum == 0)
break; /* End of source file */
if (i = (InF->UPtr == 0)) {
if (Quiet < 0)
fprintf (stderr, "%d\n", InF->Line);
close (In.fd); /* Close inner file */
In.fd = NULL;
}
NextFNS = InF->NPtr; /* Release space on name stack */
InFNum--; /* Return to outer file */
InF++;
if (InFNum < OuterMac)
OuterMac = 0; /* End of outer macro */
if (InF->UPtr == 0) {
if (i)
ShowFile (FALSE); /* Inner file -> outer file */
else if (InnrFMac) {
ShowFile (FALSE); /* Inner user macro -> file */
InnrFMac = FALSE;
}
if (In.fd == NULL) {
In.fd = open (InF->NPtr, 0);
lseek (In.fd, InF->Pos, 0);
In.Ptr = In.Lim = In.Buf;
}
} else if (i) {
InnrFMac = TRUE; /* Inner file -> outer user macro */
}
}
LineCount++; /* Bump line counter */
(InF->Line)++;
if ((Label[0] != '\0') && (Label[0] != '\\'))
if ((Label[0] < '0') || (Label[0] > '9'))
LabLine = LineCount; /* Save line number of label */
if (Quiet != 0) {
i = (Quiet < 0 ? InF->Line : LineCount);
if ((i % Quiet) == 0) { /* Display progress */
ShowLine (i);
}
}
ErrLim = AddrAdv = InstSize = nO = nS = nD = nX = 0;
PrntAddr = FALSE;
if (LineCount == DebugStart)
fprintf (stderr, "%d\n", LineCount);
if ((LineCount >= DebugStart) && (LineCount <= DebugEnd))
printf ("%9lx %5d %s\n", AddrCnt, LineCount, Line);
return (eofflag);
}
GetMacLine (dummy) int dummy;
/* Gets the next stored user macro line. */
{
register char *s, *t;
register struct NameChunk *np;
s = InF->UPtr;
if (*s == '\n') { /* Continue in next chunk */
np = NameStart;
while ((s < (char *) np)
|| (s > ((char *) np + CHUNKSIZE)))
np = np->Link; /* Find the chunk we're in */
InF->UPtr = (char *) (np->Link) + sizeof (struct NameChunk *);
s = InF->UPtr;
}
t = Line;
while (*t++ = *s++) /* Copy InF->UPtr to Line, then bump InF->UPtr. */
; /* (It's faster than doing a strcpy followed */
InF->UPtr = s; /* by a strlen to bump the pointer.) */
}
int GetLine (dummy) int dummy;
/* Gets the next line from the current input file and leaves it in Line.
Returns TRUE if end of file has been reached, FALSE otherwise. */
{
register char *s;
register int c;
register char *t, *m, *l;
s = Line;
t = In.Ptr; /* Use a register for speed */
m = Line + MAXLINE - 1; /* Limit of "Line" */
while (1) { /* Get Line, expanding tabs */
if (t >= In.Lim) {
t = In.Buf; /* Re-fill the buffer */
In.Lim = In.Buf + read (In.fd, In.Buf, BUFFSIZE);
if (In.Lim == In.Buf) {
*s = '\0'; /* End of file */
In.Ptr = t;
return (s <= Line); /* Last line might have no \n */
}
}
if ((c = *t++) == '\n') {
break;
}
#ifdef MSDOS
if (c == 26) {
*s = '\0'; /* Catch MS-DOS EOF char. */
In.Ptr = t;
return (s <= Line);
}
if ((s < m) && (c != 13)) { /* Ignore excess */
#else
if (s < m) { /* Ignore excess */
#endif
if ((c == '\t') && !KeepTabs) {
l = Line + (((s - Line) + 8) & ~7);
if (l > m)
l = m; /* Tabbed off the end */
while (s < l)
*s++ = ' '; /* Expand tabs */
} else {
*s++ = c; /* Normal character */
}
}
}
*s = '\0'; /* Terminate the string in Line */
In.Ptr = t;
return (FALSE);
}
SubArgs (dummy) int dummy;
/* Macro argument substitution routine */
{
int j;
register char *s, *t, *x;
char subline[MAXLINE];
if (InF->NArg == -1)
return; /* Not a macro - leave Line alone */
s = Line;
t = subline;
while (*s) {
if ((*t++ = *s++) != '\\') {
continue;
}
x = s--;
t--;
if (*x == '@') { /* \@ - substitute macro number */
x = t;
*t++ = '.';
j = InF->MCnt % 1000;
*t++ = j / 100 + '0';
j = j % 100;
*t++ = j / 10 + '0';
*t++ = j % 10 + '0';
strcpy (t, s+2); /* Remainder of Line */
strcpy (Line, subline); /* Replace Line */
while (*t != '\\') /* Check for more substitutions */
if (*t)
t++;
else
return; /* All done */
s = t - subline + Line; /* Do the next substitution */
continue;
}
if ((*x < '0') || (*x > '9')) {
s++; /* False alarm - it's a */
t++; /* named local variable */
continue;
}
s++;
*t = '\0';
j = 0; /* Get argument index */
while ((*s >= '0') && (*s <= '9')) {
j *= 10;
j += *s++ - '0'; /* Current digit */
}
if (j == 0)
strcpy (t, MacSize); /* Macro call size */
else if ((j > 0) && (j <= InF->NArg)) {
x = InF->NPtr;
while (j > 0) { /* Find argument */
x += strlen (x) + 1;
j--;
}
strcpy (t, x); /* Insert it */
}
while (*t)
t++; /* Skip over replacement */
strcpy (t, s); /* Remainder of Line */
strcpy (Line, subline); /* Replace Line */
while (*t != '\\') /* Check for more substitutions */
if (*t)
t++;
else
return; /* All done */
s = t - subline + Line; /* Do the next substitution */
}
}
GetParts (dummy) int dummy;
/* Break up Line into its component parts. */
{
register char *s, *x;
Size = S0;
s = Line;
if (!isspace (*s)) {
x = Label;
while (!isspace (*s) && (*s != ';') && (*s != '\0'))
*x++ = *s++; /* Get the label */
*x-- = '\0';
while (*x == ':') {
*x-- = '\0'; /* Strip trailing colon(s) */
if (x < Label)
break;
}
}
while (OpLoc == 0) {
while (isspace (*s))
s++; /* Skip over to opcode */
if ((*s == ';') || (*s == '\0'))
return; /* End of statement image */
OpLoc = s - Line;
x = OpCode;
while (!isspace (*s) && (*s != ';') && (*s != '\0'))
*x++ = *s++; /* Get the opcode */
*x-- = '\0';
if (*x == ':') { /* It's actually a label */
if (Label[0]) {
Error (OpLoc, MultLab); /* Multiple labels */
} else {
while ((x >= OpCode) && (*x == ':'))
*x-- = '\0';
strcpy (Label, OpCode); /* Get the label */
}
OpLoc = 0; /* Try again for opcode */
OpCode[0] = '\0';
}
}
for (x = OpCode; *x; x++) /* Convert OpCode */
*x = toupper(*x); /* to upper case */
x -= 2;
if ((x < OpCode) || (*x != '.')) /* If no explicit size is given */
Size = Word; /* default to Word (16 bits). */
else {
*x++ = '\0'; /* Chop off size extension */
switch (*x) {
case 'B': /* Byte */
case 'S': /* Short Branch */
Size = Byte;
break;
case 'L': /* Long */
Size = Long;
break;
default:
Size = Word; /* Default to Word */
break;
}
}
while (isspace(*s))
s++; /* Skip over to operands */
if ((*s == ';') || (*s == '\0'))
return; /* There are no operands */
SrcLoc = s - Line;
s = GetField (s, SrcOp); /* Op1 (source) */
if (*s == ',')
s++;
if (!isspace (*s) && (*s != '\0') && (*s != ';')) {
DestLoc = s - Line;
s = GetField (s, DestOp); /* Op2 (destination) */
}
}
ShowFile (newline) int newline;
/* Shows the current file name if we're displaying all input modules.
If "newline" is TRUE, go to a new line before displaying the name. */
{
if ((Quiet < 0) && (InF->UPtr == 0))
if (newline)
fprintf (stderr, "\n%s line ", InF->NPtr);
else
fprintf (stderr, "%s line ", InF->NPtr);
}
ShowLine (i) register int i;
/* Shows the current line number and backs up over it. */
{
if (i >= 10000)
fprintf (stderr, "%5d\b\b\b\b\b", i);
else if (i >= 1000)
fprintf (stderr, "%4d\b\b\b\b", i);
else if (i >= 100)
fprintf (stderr, "%3d\b\b\b", i);
else if (i >= 10)
fprintf (stderr, "%2d\b\b", i);
else
fprintf (stderr, "%1d\b", i);
fflush (stderr); /* Make sure it gets out */
}
char *GetField (s, d) register char *s, *d;
/* Gets a field from "s", returns result in "d".
Stops on the first comma, semicolon, or white space not
enclosed within apostrophes or parentheses.
Returns stopping location.
If already at end of "s", "d" is set to null string. */
{
register char c;
register int parncnt, instring;
instring = FALSE;
parncnt = 0;
while (c = *s) {
if (instring) {
*d++ = c;
} else {
if (isspace(c) || (c == ';'))
break;
else if ((c == ',') && (parncnt == 0))
break;
else {
*d++ = c;
if (c == '(')
parncnt++;
else if (c == ')')
parncnt--;
}
}
if (c == '\'')
instring = !instring;
s++;
}
*d = '\0';
return (s);
}
long GetValue (operand, loc) char *operand; int loc;
/* Determines value of expression */
/* Hunk2 is set to hunk number of result (ABSHUNK if absolute).
If the expression consists solely of self-defining terms,
DefLine2 is set to zero. Otherwise, DefLine2 is set
to the highest statement number in which any symbol in
the expression was defined. If the expression contains
any undefined symbols, DefLine2 is set to NODEF.
The following code is based on a regular-to-Polish expression
converter described in "A Guide to FORTRAN IV Programming"
by Daniel D. McCracken (John Wiley & Sons, Inc. 1965,
3rd printing August 1968). However, rather than generating
the entire Polish expression, this routine will evaluate
and combine two terms as soon as an operator of lower
precedence is encountered. */
{
register char *o, *s;
char tempop[MAXLINE];
int oloc, parncnt, nextprec, instring;
long templong;
struct TermStack *origterm;
instring = (unsigned int) '~';
OpPrec[instring] = 9; /* Fudge IsOperator for speed */
nextprec = TRUE; /* Assume there's only a single term */
for (o = operand; *o; o++) {
if (IsOperator (o)) {
nextprec = FALSE; /* It's not a single term */
break;
}
}
instring = (unsigned int) '~';
OpPrec[instring] = '\0'; /* Restore IsOperator */
if (nextprec)
return(CalcValue(operand,loc)); /* Short cut for single term */
Hunk2 = ABSHUNK;
parncnt = DefLine2 = 0;
o = (char *) (((long) NextFNS + 3L) & ~3L);
origterm = Term = (struct TermStack *) o; /* Term stack */
Ops = (struct OpStack *) InF; /* Operator stack */
Ops--;
ParseSpace (0);
Ops->chr = ' '; /* Prime the operator stack */
Ops->prec = -1;
if ((char *) Ops < Low2)
Low2 = (char *) Ops;
/* Get all tokens.
Terms are evaluated, and operator precedence is determined.
Left and right parentheses are given a precedence of
1 and 2 respectively.
Binary operators are given precedence values starting at 3.
Unary plus is ignored.
Unary minus is converted to zero minus the remainder of
of the expression - its precedence is set to 9 to
ensure that the simulated unary operator is evaluated
before the remainder of the expression.
Logical not (~), being another unary operator, is converted
to -1 exclusive-ORed with the remainder of the expression.
Its precedence is also set to 9. */
o = operand; /* Current position in operand */
while (1) {
while (*o == '(') { /* Left parenthesis */
Ops--;
ParseSpace (0);
Ops->chr = '(';
Ops->prec = 1;
if ((char *) Ops < Low2)
Low2 = (char *) Ops;
parncnt++;
o++;
}
if ((*o == '+') || (*o == '-') || (*o == '~')) { /* Unary op */
if (*o != '+') { /* Ignore unary plus */
Ops--;
ParseSpace (sizeof (struct TermStack));
Term->value = (*o == '-') ? 0 : -1; /* Dummy value */
Term->hunk = ABSHUNK;
Term->oploc = loc + (o - operand);
Term->defline = 0;
Term++;
if ((char *) Term > High2)
High2 = (char *) Term;
Ops->chr = *o; /* Now get the operator itself */
Ops->prec = 9; /* Do it ASAP */
if ((char *) Ops < Low2)
Low2 = (char *) Ops;
}
o++;
if (*o == '(')
continue; /* Inner parenthesized expression */
}
oloc = loc + (o - operand);
s = tempop; /* Get a term */
if (*o == '*') { /* It's a location counter reference, */
*s++ = *o++; /* not a multiplication operator! */
} else {
if (IsOperator (o) || (*o == '\0')) {
Error (oloc, OperErr); /* Unexpected operator or no terms */
return (0L);
}
instring = (unsigned int) '~';
OpPrec[instring] = 9; /* Fudge IsOperator for speed */
instring = FALSE;
while (*o) {
if (*o == '\'')
instring=!instring; /* String delimiter */
if (!instring && IsOperator (o))
break; /* Found an operator - stop */
*s++ = *o++; /* Get a character */
}
instring = (unsigned int) '~';
OpPrec[instring] = '\0'; /* Restore IsOperator */
}
*s = '\0';
ParseSpace (sizeof (struct TermStack));
Term->value = CalcValue (tempop, oloc);
Term->hunk = Hunk2;
Term->oploc = oloc;
Term->defline = DefLine2;
Term++;
if ((char *) Term > High2)
High2 = (char *) Term;
Hunk2 = DefLine2 = 0;
while (*o == ')') { /* Right parenthesis */
if (parncnt == 0) {
Error ((int) (loc + (o - operand)), OperErr);
return (0L);
}
CondCalc (2); /* Unstack what we can */
if (Ops->chr == '(')
Ops++; /* Drop paired parentheses */
else {
Ops--;
ParseSpace (0);
Ops->chr = ')'; /* Stack parenthesis for now */
Ops->prec = 2;
if ((char *) Ops < Low2)
Low2 = (char *) Ops;
}
parncnt--;
o++;
}
if (*o) {
nextprec = IsOperator (o);
if ((nextprec == 0) || (*o == '(')) {
Error ((int) (loc + (o - operand)), OperErr);
return (0L); /* Expected an operator */
}
CondCalc (nextprec); /* Unstack what we can */
Ops--;
ParseSpace (0);
Ops->chr = *o; /* Stack the next operator */
Ops->prec = nextprec;
if ((char *) Ops < Low2)
Low2 = (char *) Ops;
if ((*o == '<') || (*o == '>'))
o++; /* Skip over two-character operator */
o++;
} else {
if (parncnt) {
Error ((int) (loc + (o - operand)), OperErr);
return (0L); /* Too many left parentheses */
}
CondCalc (0); /* Unstack what's left */
if (--Term != origterm) /* Should be only one term left */
Error (Term->oploc, OperErr); /* Parser bug? */
Hunk2 = Term->hunk;
DefLine2 = Term->defline;
return (Term->value); /* Final value */
}
}
}
CondCalc (newprec) int newprec;
/* As long as the top operator on the operator stack has a precedence
greater than or equal to the contents of "newprec", this routine
will pop the two top terms from the term stack, combine them
according to the operator on the top of the operator stack (which
is also popped), and push the result back onto the term stack. */
{
while (Ops->prec >= newprec) { /* Unstack an operator */
Term -= 2;
if (Ops->chr == '+') { /* Relocatable addition */
if (Term->hunk == ABSHUNK)
Term->hunk = (Term+1)->hunk; /* A+R */
else if ((Term+1)->hunk != ABSHUNK) {
Error ((Term+1)->oploc, RelErr); /* R+R - error */
Term->hunk = ABSHUNK; /* Make it absolute */
}
} else if (Ops->chr == '-') { /* Subtraction */
if (Term->hunk == (Term+1)->hunk)
Term->hunk = ABSHUNK; /* R-R - absolute */
else if ((Term+1)->hunk != ABSHUNK) { /* R-R across hunks */
Error ((Term+1)->oploc, RelErr); /* is an error - */
Term->hunk = ABSHUNK; /* make it absolute */
}
} else if ((Term->hunk != ABSHUNK)
|| ((Term+1)->hunk != ABSHUNK)) {
Error (Term->oploc,RelErr); /* All other operations */
Term->hunk = ABSHUNK; /* must be absolute */
}
if ((Term+1)->defline > Term->defline) /* Definition */
Term->defline = (Term+1)->defline; /* line nos. */
switch (Ops->chr) { /* Perform the operation */
case '+':
Term->value += (Term+1)->value;
break;
case '-':
Term->value -= (Term+1)->value;
break;
case '*':
Term->value *= (Term+1)->value;
break;
case '/':
if ((Term+1)->value)
Term->value /= (Term+1)->value;
else
Term->value = 0; /* Don't divide by zero */
break;
case '&':
Term->value &= (Term+1)->value;
break;
case '!':
case '|':
Term->value |= (Term+1)->value;
break;
case '<':
Term->value <<= (Term+1)->value;
break;
case '>':
Term->value >>= (Term+1)->value;
break;
case '~':
Term->value ^= (Term+1)->value;
break;
default:
Error (Term->oploc, OperErr); /* Parser bug? */
break;
}
Term++;
Ops++;
}
}
int IsOperator (o) register char *o;
/* Tests whether "o" points to a valid operator or parenthesis.
Returns the precedence of the operator, or 0 if it isn't one. */
{
register unsigned int i;
i = (unsigned int) *o;
i = (unsigned int) OpPrec[i];
if (i != 6)
return ((int) i);
if (*(o+1) == *o)
return ((int) i); /* << or >> */
else
return (0); /* False alarm */
}
long CalcValue (operand, loc) char *operand; int loc;
/* Evaluates a single term (called by GetValue).
Hunk2 receives relative hunk number (ABSHUNK if absolute).
If the value is a symbol, DefLine2 is set to the line number
where it was defined, or NODEF if it is undefined.
For self-defining terms, DefLine2 is set to zero. */
{
register long result; /* Result is calculated here */
register char *s, *numstart;
register int radix;
int neg, overflow;
char maxdig; /* Highest valid digit in current radix */
char delim; /* String delimiter (' or ") */
Hunk2 = ABSHUNK; /* Assume value is absolute */
DefLine2 = 0; /* and self-defining */
result = 0;
overflow = FALSE;
if (neg = (*operand == '-'))
numstart = operand + 1; /* Negative value */
else
numstart = operand; /* Positive value */
if ((*numstart >= '0') && (*numstart <= '9')) {
radix = 10; /* Decimal number */
maxdig = '9';
} else if (*numstart == '$') {
radix = 16; /* Hexadecimal number */
maxdig = '9';
} else if (*numstart == '@') {
radix = 8; /* Octal number */
maxdig = '7';
} else if (*numstart == '%') {
radix = 2; /* Binary number */
maxdig = '1';
} else
radix = 0; /* Not a number */
if (radix != 0) { /* Some sort of number */
result = 0;
if (radix != 10)
numstart++; /* Allow for type character */
for (s = numstart; *s; s++) {
result *= radix;
if ((*s >= '0') && (*s <= maxdig)) {
result += (*s - '0');
} else if (radix == 16) {
if ((*s >= 'A') && (*s <= 'F'))
result += (*s - 'A' + 10);
else if ((*s >= 'a') && (*s <= 'f'))
result += (*s - 'a' + 10);
else
Error (loc + s - operand, OperErr);
} else if (!neg && (radix==10) && (*s=='$') && (*(s+1)=='\0')) {
if (ReadSymTab (operand)) { /* Look up local label */
result = Value; /* Get its value */
AddRef (LineCount); /* Add reference */
if (Sym->Flags & 0x60)
Error (loc, AddrErr); /* Can't use a register equate */
} else {
Error (loc, Undef); /* Undefined */
}
break;
} else {
Error (loc + s - operand, OperErr);
}
}
} else if ((*operand == '\'') || (*operand == '"')) {
delim = *operand; /* Character value delimiter */
result = 0;
s = operand + 1;
while (1) {
if (*s == '\0') {
Error (loc+s-operand,NoStrEnd); /* End is missing */
result = 0;
break;
}
if (*s == delim) { /* End of string? */
if (*(++s) != delim) /* Check next character */
break; /* End of string */
} /* Otherwise it's an apostrophe in the string */
if ((result & 0xFF000000L) && !overflow) {
Error (loc+s-operand, SizeErr); /* Result overflowed */
overflow = TRUE;
result = 0;
}
if (!overflow)
result = (result << 8) + *s;
s++;
}
} else if ((*operand == '*') && (*(operand+1) == '\0')) {
result = AddrCnt; /* Value of location counter */
Hunk2 = CurrHunk; /* Use current section's hunk number */
} else {
if (ReadSymTab (operand)) { /* Look up symbol */
result = Value; /* Get its value */
AddRef (LineCount); /* Add reference */
if (Sym->Flags & 0x60)
Error (loc, AddrErr); /* Can't use a register equate */
} else if (strcmp (operand, "NARG") == 0) {
result = InF->NArg; /* Number of arguments */
if (result == -1)
result = 0; /* No arguments outside macros */
} else
Error (loc, Undef); /* Undefined */
}
if (neg) {
result = -result; /* Negative value */
if (Hunk2 != ABSHUNK)
Error (loc, RelErr); /* Must be absolute */
}
return (result);
}
AddSymTab (label, value, hunk, line, flags)
char label[];
long value, hunk;
int line, flags;
/* Inserts a new entry to the symbol table and increments NumSyms.
"Sym" will be set to point to the new entry.
If the label is a local label (i.e. the first character is
a numeric digit or a backslash), the current contents of LabLine
will be converted to characters and appended to the label before
it is added. If the first character of the label is a backslash
(i.e. a named local variable) a dollar sign will be appended
to the label ahead of the value of LabLine. */
{
char wlab[MAXLINE], wnum[6];
register struct SymTab *chainsym, **hashindex;
strcpy (wlab, label);
if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
if (label[0] == '\\')
strcat (wlab, "$");
sprintf (wnum, "%d", LabLine); /* If it's a local label, */
strcat (wlab, wnum); /* append LabLine */
}
Sym = SymLim; /* Pointer to new entry */
SymLim++; /* Bump limit pointer */
if (((char *) SymLim - (char *) SymCurr) > CHUNKSIZE) {
Sym = (struct SymTab *) malloc ((unsigned) CHUNKSIZE);
if (Sym == NULL)
quit_cleanup ("Out of memory!\n");
SymCurr->Link = Sym; /* Link from previous chunk */
SymCurr = Sym; /* Make the new chunk current */
SymCurr->Link = NULL; /* Clear forward pointer */
Sym++; /* Skip over pointer entry */
SymLim = Sym; /* New table limit */
SymLim++; /* Bump it */
}
Sym->Link = NULL; /* Clear hash chain link */
Sym->Nam = AddName(wlab,0); /* Pointer to symbol */
Sym->Val = value; /* Value */
Sym->Hunk = hunk; /* Hunk number */
Sym->Defn = line; /* Statement number */
Sym->Flags = flags; /* Flags */
Sym->Ref1 = NULL; /* Reference pointer */
NumSyms++; /* Count symbols */
hashindex = HashIt (wlab); /* Get hash index */
if (*hashindex == NULL) {
*hashindex = Sym; /* First entry in this hash chain */
return;
}
chainsym = *hashindex;
while (chainsym->Link != NULL)
chainsym = chainsym->Link; /* Scan for end of hash chain */
chainsym->Link = Sym; /* Insert new entry at the end */
}
char *AddName (name, macflag) char *name; int macflag;
/* Adds the name in "name" to the name heap.
"macflag" can take any of the following values:
0 - normal name
1 - first line of macro text - there must be room on the
name heap for at least one character following "name".
2 - additional lines of macro text - make sure there's room
for an addition character (as in 1 above). Also,
if it is necessary to allocate a new chunk of memory,
first place a newline character after the last entry
in the old chunk. This acts as a flag when retrieving
lines of macro text during an expansion.
This function returns a pointer to "name" on the name heap. */
{
register char *s, *t;
struct NameChunk *n;
s = NameLim + strlen(name) + 1; /* The new entry ends here */
if (macflag) /* If this is a macro, */
s++; /* allow for continuation flag. */
if ((s - (char *) NameCurr) > CHUNKSIZE) { /* If this chunk is full */
if (macflag == 2) /* If this is more macro text */
*NameLim = '\n'; /* insert continuation flag. */
n = (struct NameChunk *) malloc ((unsigned) CHUNKSIZE);
if (n == NULL)
quit_cleanup ("Out of memory!\n");
NameCurr->Link = n; /* Link from previous chunk */
NameCurr = n; /* Make the new chunk current */
NameCurr->Link = NULL; /* Clear forward pointer */
s = (char *) NameCurr;
NameLim = s + sizeof (char *); /* Skip over pointer entry */
}
s = NameLim;
t = name;
while ((*s++ = *t++) != '\0') /* Store name */
;
t = NameLim;
NameLim = s; /* Update table limit */
return (t);
}
int ReadSymTab (label) char label[];
/* Searches the symbol table for the given label.
If not found, points Sym to NULL and returns FALSE.
If found, points Sym to the proper table entry,
and sets up the following fields:
Value - value of symbol
Hunk2 - hunk number in which symbol resides
ABSHUNK if value is absolute
ones complement of symbol table index if external
DefLine2 - statement number in which symbol was defined
(NODEF if undefined )
If the label is a local label (i.e. the first character is
numeric), the current contents of LabLine will be converted
to characters and appended to the label before it is searched.
(This matches the way AddSymTab added the label to the table.)
If the first character of the label is a backslash (i.e. a
named local variable) a dollar sign will be appended to the
label ahead of the value of LabLine. */
{
char wlab[MAXLINE], wnum[6];
register struct SymTab **hashindex;
strcpy (wlab, label);
if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
if (label[0] == '\\')
strcat (wlab, "$");
sprintf (wnum, "%d", LabLine); /* If it's a local label, */
strcat (wlab, wnum); /* append LabLine */
}
hashindex = HashIt (wlab); /* Get hash index */
Sym = *hashindex;
while (Sym != NULL) {
if (strcmp (Sym->Nam, wlab) == 0) {
Value = Sym->Val; /* Found it */
Hunk2 = Sym->Hunk;
if (!(Sym->Flags & 9))
Hunk2 &= 0x0000FFFFL; /* Isolate hunk number */
DefLine2 = Sym->Defn;
return (TRUE);
}
Sym = Sym->Link;
}
Value = 0; /* Didn't find it - */
Hunk2 = ABSHUNK; /* set value to absolute zero */
DefLine2 = NODEF;
return (FALSE);
}
struct SymTab **HashIt (label) register char *label;
/* Returns a pointer to the hash table entry corresponding to "label" */
{
register unsigned i;
i = 0;
while (*label) {
i = ((i << 3) - i + *label++) % HashSize;
}
return (Hash + i);
}
struct SymTab *NextSym (sym) register struct SymTab *sym;
/* Returns a pointer to the next symbol table entry in memory,
or NULL if there are no more symbol table entries.
SymChunk and SymChLim must be properly set up. */
{
register struct SymTab *sp;
if (sym == NULL)
return (NULL); /* We're nowhere - get out */
sym++;
sp = sym;
sp++;
if ((SymLim >= SymChunk) && (SymLim <= SymChLim))
if (sym >= SymLim)
return (NULL); /* End of symbol table entries */
if (sp > SymChLim) {
if ((SymChunk = SymChunk->Link) == NULL)
return (NULL); /* End of the last chunk */
SymChLim = (struct SymTab *) ((char *) SymChunk + CHUNKSIZE);
sym = SymChunk;
sym++; /* First entry in the new chunk */
}
return (sym);
}
AddRef (linenum) int linenum;
/* Adds "linenum" to the list of references
for the symbol pointed to by Sym. */
{
register int i;
register struct Ref *ref, *prevref;
if (!Pass2)
return; /* Pass 2 only! */
if (!XrefList)
return; /* No cross-reference */
prevref = NULL;
ref = Sym->Ref1;
while (ref) { /* Chase pointers */
for (i = 0; i < MAXREF; i++) { /* Scan reference entry */
if (ref->RefNum[i] == 0) { /* for an empty slot */
ref->RefNum[i] = linenum; /* Insert new line number */
return;
}
}
prevref = ref; /* Remember where we were */
ref = ref->NextRef; /* Link to the next entry */
}
ref = RefLim; /* Pointer to new entry */
RefLim++; /* Bump limit pointer */
if (((char *) RefLim - (char *) SymCurr) > CHUNKSIZE) {
ref = (struct Ref *) malloc ((unsigned) CHUNKSIZE);
if (ref == NULL) {
fprintf (stderr, " \nOut of memory");
fprintf (stderr, " - cross-reference disabled.\n");
XrefList = FALSE;
return;
}
SymCurr->Link = (struct SymTab *) ref; /* Link from prev. chunk */
SymCurr = (struct SymTab *)ref; /* Make the new chunk current */
SymCurr->Link = NULL; /* Clear forward pointer */
ref++; /* Skip over pointer entry */
RefLim = ref; /* New table limit */
RefLim++; /* Bump it */
}
ref->NextRef = NULL; /* Pointer to next entry */
ref->RefNum[0] = linenum; /* First reference in new entry */
for (i = 1; i < MAXREF; i++)
ref->RefNum[i] = 0; /* Clear remaining slots */
if (prevref == NULL)
Sym->Ref1 = ref; /* Link to first entry */
else
prevref->NextRef = ref; /* Link to next entry */
}
int CountNest (s) register char *s;
/* Returns 1 if "s" contains any IF statement (i.e. IFEQ, etc.).
Returns -1 if "s" contains "ENDC" or "ENDIF".
Returns 0 in all other cases. */
{
if (strcmp (s, "ENDC") == 0)
return (-1);
else if (strcmp (s, "ENDIF") == 0)
return (-1);
else if (*s++ != 'I')
return (0);
else if (*s++ != 'F')
return (0);
else if (strcmp (s, "EQ") == 0)
return (1);
else if (strcmp (s, "NE") == 0)
return (1);
else if (strcmp (s, "GT") == 0)
return (1);
else if (strcmp (s, "GE") == 0)
return (1);
else if (strcmp (s, "LT") == 0)
return (1);
else if (strcmp (s, "LE") == 0)
return (1);
else if (strcmp (s, "C" ) == 0)
return (1);
else if (strcmp (s, "NC") == 0)
return (1);
else if (strcmp (s, "D" ) == 0)
return (1);
else if (strcmp (s, "ND") == 0)
return (1);
else
return (0);
}
Heap2Space (n) int n;
/* Die if we can't find "n" bytes on the secondary heap. */
{
if ((NextFNS + n) > (char *) InF) {
printf ("\n%5d %s\n", LineCount, Line);
quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
}
}
ParseSpace (n) int n;
/* Special version of Heap2Space for the expression parser */
{
if (((char *) Term + n) > (char *) Ops) {
printf ("\n%5d %s\n", LineCount, Line);
quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
}
}
SHAR_EOF
cat << \SHAR_EOF > Operands.c
/*------------------------------------------------------------------*/
/* */
/* MC68000 Cross Assembler */
/* */
/* Copyright (c) 1985 by Brian R. Anderson */
/* */
/* Operand processor - January 10, 1989 */
/* */
/* This program may be copied for personal, non-commercial use */
/* only, provided that the above copyright notice is included */
/* on all copies of the source code. Copying for any other use */
/* without the consent of the author is prohibited. */
/* */
/*------------------------------------------------------------------*/
/* */
/* Originally published (in Modula-2) in */
/* Dr. Dobb's Journal, April, May, and June 1986. */
/* */
/* AmigaDOS conversion copyright 1989 by Charlie Gibbs. */
/* */
/*------------------------------------------------------------------*/
#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"
/* Functions */
extern int LineParts(), Instructions(), ObjDir();
extern int ReadSymTab(), OpenIncl(), CountNest();
extern long AddrBndW(), AddrBndL(), GetValue(), CalcValue();
extern char *AddName(), *GetField();
extern struct SymTab *NextSym();
extern struct SymTab **HashIt();
int GetArgs(), GetAReg(), GetInstModeSize(), GetMultReg();
int GetArgs (name) char *name;
/* Gets macro arguments and adds them to FNStack after adding "name".
Returns the number of arguments added to the stack.
Note that this might not be the full number of arguments
provided if the stack overflowed. */
{
register char *s, *t;
int narg, instring;
char currarg[MAXLINE]; /* Current argument */
narg = strlen (name) + 1;
Heap2Space (narg); /* Find space for name */
strcpy (NextFNS, name); /* Add name to stack */
NextFNS += narg; /* Bump pointer */
if (NextFNS > High2)
High2 = NextFNS; /* Update high-water mark */
narg = 0; /* Argument counter */
s = Line + SrcLoc; /* Now scan Line */
while (!isspace(*s) && (*s != ';') && (*s != '\0')) {
t = currarg;
if (instring = (*s == '<')) /* String delimiter */
s++;
while (1) {
if (*s == '\0')
break; /* End of line */
if (instring) {
if (*s == '>') {
s++;
break; /* End of string */
}
} else {
if ((*s == ',') /* End of operand */
|| isspace(*s) /* End of all operands */
|| (*s == ';')) /* Start of comments */
break;
}
*t++ = *s++; /* Get a character */
}
*t++ = '\0';
Heap2Space (t - currarg); /* Check for space */
strcpy (NextFNS, currarg); /* Store argument */
NextFNS += t - currarg; /* Next available space */
if (NextFNS > High2)
High2 = NextFNS; /* High-water mark */
narg++; /* Count arguments */
if (*s == ',')
s++; /* Skip over separator */
}
return (narg); /* Successful completion */
}
EffAdr (EA, Bad) register struct OpConfig *EA; int Bad;
/* Adds effective address field to Op (BITSET representing opcode) */
{
if ((1 << (EA->Mode - 1)) IN Bad) {
Error (EA->Loc, ModeErr); /* Invalid mode */
return;
} else if (EA->Mode > 12) /* Special modes */
return;
else if (EA->Mode < 8) /* Register direct or indirect */
Op |= ((EA->Mode - 1) << 3) | EA->Rn;
else
Op |= 0x0038 | (EA->Mode - 8); /* Absolute modes */
OperExt (EA);
}
OperExt (EA) register struct OpConfig *EA;
/* Calculate operand Extension word, and check range of operands */
{
switch (EA->Mode) {
case AbsL:
break; /* No range checking needed */
case AbsW:
case ARDisp:
case PCDisp:
if ((EA->Value < -32768) || (EA->Value > 32767))
Error (EA->Loc, SizeErr);
break;
case ARDisX:
case PCDisX:
if ((EA->Value < -128) || (EA->Value > 127))
Error (EA->Loc, SizeErr);
EA->Value &= 0x00FF; /* Displacement */
EA->Value |= EA->Xn << 12; /* Index reg. */
if (EA->X == Areg) EA->Value |= 0x8000; /* Addr. Reg. */
if (EA->Xsize == Long) EA->Value |= 0x0800; /* Long reg. */
break;
case Imm:
if (Size == Word) {
if ((EA->Value < -32768) || (EA->Value > 65535L))
Error (EA->Loc, SizeErr);
} else if (Size == Byte)
if ((EA->Value < -128) || (EA->Value > 255))
Error (EA->Loc, SizeErr);
break;
}
}
GetOperand (oper, op, pcconv)
char *oper; register struct OpConfig *op; int pcconv;
/* Finds mode and value for source or destination operand.
If PC-relative addressing is permitted, "pcconv" gives the
offset to the displacement word; otherwise "pcconv" is zero. */
{
register char *s, *t;
register int i;
char *opend;
char UCoper[MAXLINE], tempop[MAXLINE];
int rloc;
long templong;
op->Value = op->Defn = 0;
op->Mode = Null;
op->X = X0;
op->Hunk = ABSHUNK;
if (*oper == '\0')
return; /* Nothing to process */
s = oper;
t = UCoper;
while (*t++ = toupper (*s++)) /* Upper-case version */
;
opend = s - 2; /* Last character of operand */
if (*oper == '#') { /* Immediate */
op->Value = GetValue (oper+1, (op->Loc)+1);
op->Mode = Imm;
op->Hunk = Hunk2;
op->Defn = DefLine2;
return;
}
i = IsRegister (oper, opend-oper+1);
if (i >= 0) {
op->Mode = (i & 8) ? ARDir : DReg; /* Register type */
op->Rn = i & 7; /* Register number */
return;
} else if (i == -2) {
op->Mode = MultiM; /* Equated register list */
op->Value = Sym->Val;
return;
} else if ((*oper == '(') && (*opend == ')')) {
i = IsRegister (oper+1, opend-oper-1);
if (i >= 8 && i <= 15) {
op->Mode = ARInd; /* Address Register indirect */
op->Rn = i - 8;
return;
} else if (i != -1) {
Error (op->Loc, AddrErr); /* Data register is invalid */
return;
} /* else may be parenthesized expression */
} else if ((*oper == '(') /* Post-increment */
&& (*opend == '+')
&& (*(opend-1) == ')')) {
op->Mode = ARPost;
op->Rn = GetAReg (oper+1, opend-oper-2, op->Loc + 1);
return;
} else if ((*oper == '-') /* Pre-decrement */
&& (*opend == ')')
&& (*(oper+1) == '(')) {
i = IsRegister (oper+2, opend-oper-2);
if (i >= 8 && i <= 15) {
op->Mode = ARPre;
op->Rn = i - 8;
return;
} else if (i > 0) {
Error (op->Loc, AddrErr); /* Data register is invalid */
return;
} /* else parenthesized expression with leading minus? */
} else if (strcmp (UCoper, "SR") == 0) {
op->Mode = SR; /* Status Register */
return;
} else if (strcmp (UCoper, "CCR") == 0) {
op->Mode = CCR; /* Condition Code Register */
return;
} else if (strcmp (UCoper, "USP") == 0) {
op->Mode = USP; /* User Stack Pointer */
return;
}
/* Try to split off displacement (if present).
We'll assume we have a register expression if the operand
ends with a parenthesized expression not preceded by an
operator. I know this code is a real kludge, but that's
the result of the bloody syntax. Thanks, Motorola. */
s = opend; /* Last character */
if (i = (*s == ')')) /* Trailing parenthesis? */
while (*(--s) != '(') /* Find left parenthesis */
if (s <= oper)
break;
if (s <= oper) /* Must not be at beginning */
i = FALSE;
if (i) {
if (s == (oper+1)) {
if (*oper == '-')
i = FALSE; /* Leading minus sign */
} else {
t = s - 1;
if (*t == '*') { /* Location counter? */
t--;
if (!IsOperator (t) || (*t == ')'))
i = FALSE; /* No, it's multiplication */
} else if (IsOperator (t) && (*t != ')')) {
i = FALSE; /* Preceded by an operator */
}
}
}
if (i) { /* Looks like a displacement mode */
*s = '\0';
op->Value = GetValue (oper, op->Loc); /* Displacement */
op->Hunk = Hunk2; /* Hunk number */
op->Defn = DefLine2; /* Line where defined */
*s++ = '('; /* Restore parenthesis */
rloc = op->Loc + s - oper; /* The register starts here */
s = GetField (s, tempop); /* Get address register */
if (*s == '\0') /* If there's no index register */
tempop[strlen(tempop)-1] = '\0'; /* chop parenthesis */
if ((tempop[2] == '\0')
&& (toupper (tempop[0]) == 'P')
&& (toupper (tempop[1]) == 'C')) {
op->Mode = PCDisp; /* Program Counter */
if (op->Hunk == CurrHunk) {
op->Value -= (AddrCnt+pcconv); /* Adjust displacement */
op->Hunk = ABSHUNK;
}
} else {
if ((op->Value == 0) /* If displacement is zero */
&& (op->Hunk == ABSHUNK) /* and is absolute */
&& (op->Defn < LineCount) /* and is already defined */
&& !(OpM68R IN AdrModeA)) /* and isn't for a MOVEP */
op->Mode = ARInd; /* forget the displacement. */
else
op->Mode = ARDisp; /* Address reg. w/displacement */
op->Rn = GetAReg (tempop, strlen (tempop), rloc);
}
if (*s != '\0') { /* Index register is present */
if (op->Mode == PCDisp)
op->Mode = PCDisX; /* Program Counter indexed */
else
op->Mode = ARDisX; /* Address Register indexed */
if (*s != ',')
Error (op->Loc, AddrErr); /* Bad separator */
s++; /* Skip separator */
rloc = op->Loc + s - oper; /* Start of index */
s = GetField (s, tempop); /* Get index register */
t = tempop + strlen(tempop);
if (*s == '\0')
*(--t) = '\0'; /* Chop parenthesis */
else
Error (rloc, AddrErr); /* It better be there */
t -= 2;
if ((t < tempop) || (*t != '.')) {
op->Xsize = Word; /* Size defaults to 16 bits */
t += 3;
} else {
*t++ = '\0'; /* Chop off size code */
switch (toupper (*t)) {
case 'W': /* Word */
op->Xsize = Word;
break;
case 'L': /* Long */
op->Xsize = Long;
break;
default:
Error (op->Loc+s-1-oper, SizeErr); /* Invalid size */
op->Xsize = Word; /* Make it word for now */
}
}
i = IsRegister (tempop,t-tempop-1); /* Get register */
op->Xn = i & 7; /* Index register number */
if ((i >= 0) && (i <= 7))
op->X = Dreg; /* Data Register */
else if ((i >= 8) && (i <= 15))
op->X = Areg; /* Address Register */
else
Error (rloc, AddrErr); /* Invalid register */
}
if ((op->Hunk >= 0) && (op->Hunk != ABSHUNK))
Error (op->Loc, RelErr); /* Relocatable displacement */
return;
}
if ((i = GetMultReg (oper, op->Loc)) != 0) {
op->Value = (long) i;
op->Mode = MultiM; /* Register list for MOVEM */
return;
}
op->Value = GetValue (oper, op->Loc); /* Get operand value */
op->Hunk = Hunk2;
op->Defn = DefLine2;
op->Mode = AbsL; /* Assume absolute long addressing */
if (DefLine2 < LineCount) { /* Backward reference */
if (Hunk2 < 0) {
return; /* External - leave as absolute long */
} else if (Hunk2 == CurrHunk) { /* Reference to current hunk */
if (pcconv) {
templong = op->Value-(AddrCnt+pcconv); /* PC disp. */
if ((templong >= -32768) && (templong <= 32767)) {
op->Mode = PCDisp; /* Convert to PC relative mode */
op->Value=templong; /* Adjust displacement */
op->Hunk = ABSHUNK;
}
}
} else if (Hunk2 == ABSHUNK) { /* Absolute value */
if ((op->Value >= -32768) && (op->Value <= 32767))
op->Mode = AbsW; /* Absolute word */
} else if (SmallData && (op->Value>=0) && (op->Value<=65535L)) {
op->Mode = ARDisp; /* Make it a data reference */
op->Rn = 4; /* through register A4 */
op->Value -= 32768L; /* Adjust displacement */
op->Hunk = ABSHUNK;
}
return; /* Could default to absolute long */
} else if (!SmallData) { /* Fwd. reference - if not small data */
return; /* leave as absolute long addressing */
} else if (!Pass2) { /* Forward reference, pass 1 */
op->Mode = ARDisp; /* Assume displacement */
op->Rn = 4; /* from register A4 */
op->Hunk = ABSHUNK;
return;
} else { /* On pass 2 we know what it is */
if (Hunk2 < 0) {
Error (op->Loc,FwdRef); /* External - must be 32 bits */
op->Mode = AbsW; /* Force absolute word anyway */
} else if (Hunk2 == CurrHunk) { /* It's in the current hunk */
op->Mode = PCDisp; /* Convert to PC relative mode */
op->Value -= AddrCnt + pcconv; /* Adjust displacement */
op->Hunk = ABSHUNK;
if (!pcconv || (op->Value < -32768) || (op->Value > 32767))
Error (op->Loc,FwdRef); /* It doesn't fit! */
} else if (Hunk2 == ABSHUNK) { /* It's absolute */
op->Mode = AbsW; /* It has to fit in a word */
if ((op->Value < -32768) || (op->Value > 32767))
Error (op->Loc,FwdRef); /* It doesn't fit! */
} else {
op->Mode = ARDisp; /* Assume data reference */
op->Rn = 4; /* through register A4 */
op->Value -= 32768L; /* Adjust displacement */
if ((op->Value < -32768) || (op->Value > 32767))
Error (op->Loc,FwdRef); /* It doesn't fit! */
}
}
}
int GetMultReg (oper, loc) char *oper; int loc;
/* Builds a register mask for the MOVEM instruction.
Returns the mask in the low-order portion of its value if
"oper" is a valid multiple-register list; otherwise returns 0. */
{
register char *s, *t;
register int j;
int t1, t2; /* Temporary variables for registers */
int range; /* We're processing a range of registers */
int multext; /* The result is built here */
multext = 0;
range = FALSE;
s = oper;
if (IsOperator (s))
return (0); /* Starts with an operator! */
while (1) {
for (t = s; *t; t++) {
if ((*t == '-') || (*t == '/')) {
break;
}
}
if ((multext == 0) && (*t == '\0'))
return (0); /* Reject single term */
if ((t2 = IsRegister (s, t-s)) < 0)
return (0); /* Not a recognizable register */
if (!range) {
multext |= (1 << t2); /* Single register */
t1 = t2; /* Save number in case it's a range */
} else { /* Range of registers */
range = FALSE;
if (t1 > t2) {
j = t1; /* Swap registers if backwards */
t1 = t2;
t2 = j;
}
for (j = t1; j <= t2; j++)
multext |= (1 << j); /* Mark all registers in range */
if (*t == '-')
return (0); /* Invalid range */
}
if (*t == '\0')
break; /* Normal end of operand */
if (*t++ == '-')
range = TRUE; /* Range indicator */
if (*t == '\0')
return (0); /* Premature end of operand */
s = t;
}
return (multext);
}
int GetAReg (op, len, loc) char *op; int len, loc;
/* Validate an address register specification.
Valid specifications are A0 through A7 , SP, or an EQUR label.
The address register number will be returned if it is valid.
Otherwise, Error will be called, using "loc" for the error
location (this is its only use), and zero (A0) will be returned. */
{
register int i;
i = IsRegister (op, len); /* Get register number */
if ((i >= 8) && (i <= 15))
return (i - 8); /* Valid address register */
else {
Error (loc, AddrErr); /* Not an address register */
return (0); /* Set to A0 */
}
}
int IsRegister (op, len) char *op; int len;
/* Check whether the current operand is an address or data register.
Valid specifications are D0 throuth D7, A0 through A7, SP,
or any symbol equated to a register with the EQUR directive.
Return values:
0 through 7 - data registers 0 through 7 respectively
8 through 15 - address registers 0 through 7 respectively
-1 - not a recognizable register
-2 - Equated register list for MOVEM instruction (REG) */
{
char tempop[MAXLINE];
register char *s;
register int i;
if (len == 2) { /* Two-character specification */
i = toupper (*op);
s = op + 1;
if ((i == 'S') && (toupper (*s) == 'P')) {
return (15); /* Stack Pointer */
} else if ((*s >= '0') && (*s <= '7')) {
if (i == 'A') {
return (*s - '0' + 8); /* Address Register */
} else if (i == 'D') {
return (*s - '0'); /* Data Register */
}
}
}
if (!GotEqur) /* If we have no EQURs to check */
return (-1); /* don't waste any time here. */
for (i = 0, s = op; i < len; i++) {
if (IsOperator (s))
return (-1); /* It sure isn't a label */
tempop[i] = *s++;
}
tempop[i] = '\0';
if (ReadSymTab (tempop)) {
if (Sym->Flags & 0x60) {
AddRef (LineCount); /* Found a register or list */
return ((Sym->Flags & 0x20) ? (int) Sym->Val : -2);
}
}
return (-1); /* Not a recognizable register */
}
int GetInstModeSize (Mode) register int Mode;
/* Determines the size for the various instruction modes. */
{
switch (Mode) {
case ARDisp:
case ARDisX:
case PCDisp:
case PCDisX:
case AbsW:
return (2);
case AbsL:
return (4);
case MultiM:
return (0); /* Accounted for by code generator */
case Imm:
if (Size == Long)
return (4);
else
return (2);
default:
return (0);
}
}
SHAR_EOF
# End of shell archive
exit 0
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.